package de.justphil.tcg.tcgserver.rest.resources.base;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;

import de.justphil.tcg.tcgserver.commons.i18n.I18n;
import de.justphil.tcg.tcgserver.commons.i18n.Error;
import de.justphil.tcg.tcgserver.commons.util.Base64;
import de.justphil.tcg.tcgserver.commons.util.StringUtil;
import de.justphil.tcg.tcgserver.commons.domain.User;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.Credentials;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.Res;
import de.justphil.tcg.tcgserver.commons.config.I18nConfig;
import de.justphil.tcg.tcgserver.commons.config.RestConfig;
import de.justphil.tcg.tcgserver.commons.management.DataManager;

public abstract class AbstractResource {
	
	protected Response ok() {
		return Response.status(Status.OK).build();
	}
	
	protected Response ok(Object resEntity) {
		return Response.status(Status.OK).entity(resEntity).build();
	}
	
	protected Response ok(Object resEntity, String contentType) {
		return Response.status(Status.OK).type(contentType).entity(resEntity).build();
	}
	
	protected Response ok(Object resEntity, MediaType contentType) {
		return Response.status(Status.OK).type(contentType).entity(resEntity).build();
	}
	
	protected Response created() {
		return Response.status(Status.CREATED).build();
	}
	
	protected Response created(Object resEntity) {
		return Response.status(Status.CREATED).entity(resEntity).build();
	}
	
	protected Response notModified() {
		return Response.status(Status.NOT_MODIFIED).build();
	}
	
	protected Response err(String errorKey, Status status, String locale) {
		return 	err(errorKey, status, locale, null, null);
	}
	
	protected Response err(String errorKey, Status status, List<Locale> acceptableLanguages) {
		return err(errorKey, status, acceptableLanguages, null);
	}
	
	protected Response err(String errorKey, Status status, List<Locale> acceptableLanguages, MediaType contentType) {
		String lang = getBestFittingLanguage(acceptableLanguages);
		
		return 	err(errorKey, status, lang, null, contentType);
	}
	
	protected Response err(String errorKey, Status status, String locale, MediaType contentType) {
		return 	err(errorKey, status, locale, null, contentType);
	}
	
	protected Response err(String errorKey, Status status, String locale, Map<String, String> headers, MediaType contentType) {
		ResponseBuilder rb = Response	.status(status)
										.entity( new Res(I18n.translate(
													errorKey,
													locale
										)));
		
		if (headers != null && headers.size() > 0) {
			for (String s : headers.keySet()) {
				rb = rb.header(s, headers.get(s));
			}
		}
		
		if (contentType != null) {
			rb.type(contentType);
		}
		
		return rb.build();
	}
	
	/* aaa = (a)uthenticate (a)nd (a)uthorize */
	protected User aaa(DataManager dataManager, List<Locale> acceptableLanguages, List<String> authHeaderList) {
		String lang = getBestFittingLanguage(acceptableLanguages);
		
		
		String authHeader = "";
		if (authHeaderList != null && authHeaderList.size() > 0) {
			authHeader = authHeaderList.get(0);
		}
		
		return aaa(dataManager, lang, authHeader);
	}
	
	/* aaa = (a)uthenticate (a)nd (a)uthorize */
	protected User aaa(DataManager dataManager, String locale, String authHeader) {
		AuthorizationResult ar = authenticateAndAuthorize(dataManager, locale, authHeader);
		if (ar.getResponse() != null) {
			throw new WebApplicationException(ar.getResponse());
		}
		else {
			return ar.getUser();
		}
	}
	
	private AuthorizationResult authenticateAndAuthorize(DataManager dataManager, String locale, String authHeader) {
		
		try {
			if (StringUtil.isNullOrEmpty(authHeader)) {
				String wwwAuthHeaderVal = RestConfig.HTTP_AUTHENTICATION_METHOD_BASIC + " realm=\"" + RestConfig.WWW_AUTHENTICATE_REALM + "\"";
				
				Map<String, String> headers = new HashMap<String, String>();
				headers.put(RestConfig.RES_HEADER_WWW_AUTHENTICATE, wwwAuthHeaderVal);
				
				return new AuthorizationResult(err(Error.CLIENT_ERROR_NO_CREDENTIALS, Response.Status.UNAUTHORIZED, locale, headers, null), null);
			}
			
			
			Credentials cred = StringUtil.parseAuthorizationHeader(new String(Base64.decodeFast(authHeader), "UTF-8"));
			if (cred == null) {
				return new AuthorizationResult(err(Error.CLIENT_ERROR_INVALID_AUTH_HEADER, Response.Status.UNAUTHORIZED, locale), null);
			}
			
			User user = dataManager.getUserByUsername(cred.getUsername());
			if (user == null) {
				return new AuthorizationResult(err(Error.CLIENT_ERROR_AUTH_USER_NOT_FOUND, Response.Status.UNAUTHORIZED, locale), null);
			}
			
			if (!cred.getPassword().equals(user.getPassword())) {
				return new AuthorizationResult(err(Error.CLIENT_ERROR_PASS_WRONG, Response.Status.UNAUTHORIZED, locale), null);
			}
			
			return new AuthorizationResult(null, user);
		}
		catch (UnsupportedEncodingException e) {
			return new AuthorizationResult(err(Error.SERVER_ERROR_INTERNAL, Response.Status.INTERNAL_SERVER_ERROR, locale), null);
		}
		
	}
	
	private String getBestFittingLanguage(List<Locale> acceptableLanguages) {
		String lang = null;
		for (Locale l : acceptableLanguages) {
			
			if (I18n.isSupportedLanguage(l)) {
				lang = l.getLanguage() + "-" + l.getCountry();
			}
		}
		
		if (lang == null) {
			lang = I18nConfig.DEFAULT_LOCALE;
		}
		
		return lang;
	}
}
